Skip to content

refactor(e2e): add bounded polling primitives for live readiness checks - #6367

Merged
jyaunches merged 2 commits into
NVIDIA:mainfrom
jyaunches:refactor/e2e-bounded-polling
Jul 8, 2026
Merged

refactor(e2e): add bounded polling primitives for live readiness checks#6367
jyaunches merged 2 commits into
NVIDIA:mainfrom
jyaunches:refactor/e2e-bounded-polling

Conversation

@jyaunches

@jyaunches jyaunches commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Add a deterministic bounded-polling primitive for read-only readiness checks and migrate representative sandbox-readiness and denied-log probes. State-mutating installer/onboard/rebuild retries remain explicit.

Closes #6347
Parent epic: #6346

Changes

  • Support attempt and deadline bounds, fixed/dynamic delay, abort signals, terminal states, injected timing, and last-result diagnostics.
  • Standardize attempt-numbered artifact names.
  • Migrate concurrent-gateway sandbox readiness and denied network-policy log polling.
  • Add deterministic support tests for success, exhaustion, backoff, deadlines, terminal states, and cancellation.

Verification

  • Signed/Verified commit and all hooks passed
  • npm run build:cli
  • npm run typecheck:cli
  • npm run lint
  • Polling and denied-log support tests: 7 passed
  • No mutation retries hidden by the generic helper

Signed-off-by: Julie Yaunches jyaunches@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added a shared end-to-end polling helper with retries, attempt/deadline bounds, configurable delays, abort-signal cancellation, and standardized per-attempt artifact naming.
  • Bug Fixes

    • Refactored live readiness and denied-log polling to use the shared helper, with consistent terminal-state handling and more informative failures that include the last observed outcome.
  • Tests

    • Added an e2e test suite covering polling success, retry timing, artifact naming, deadline/terminal early termination, and abort cancellation.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a948a52f-52d0-4577-8355-583bcb9f919d

📥 Commits

Reviewing files that changed from the base of the PR and between be606d4 and 6a90666.

📒 Files selected for processing (3)
  • test/e2e/fixtures/polling.ts
  • test/e2e/live/concurrent-gateway-ports.test.ts
  • test/e2e/support/e2e-polling.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/e2e/support/e2e-polling.test.ts
  • test/e2e/live/concurrent-gateway-ports.test.ts
  • test/e2e/fixtures/polling.ts

📝 Walkthrough

Walkthrough

Adds a generic bounded polling utility for e2e tests, migrates two live polling loops to use it, and adds a deterministic test suite covering the polling behavior.

Changes

Bounded polling primitive

Layer / File(s) Summary
Polling types, errors, and pollUntil implementation
test/e2e/fixtures/polling.ts
Defines PollAttempt<T>, PollOptions<T>, PollingError<T>, pollingArtifactName, and pollUntil, supporting attempt/deadline bounds, abort signal, terminal detection, and per-attempt delay/backoff.
Migrate live e2e readiness loops
test/e2e/live/concurrent-gateway-ports.test.ts, test/e2e/live/network-policy-denied-log.ts
Replaces hand-rolled retry loops for sandbox readiness and denied-reason log polling with pollUntil-based flows, using probe/accept/terminal callbacks and PollingError handling.
Deterministic tests for pollUntil
test/e2e/support/e2e-polling.test.ts
New Vitest suite covering bounded acceptance, backoff/exhaustion with recorded sleeps, deadline exhaustion, terminal termination, and abort-signal cancellation.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested labels: chore

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding bounded polling primitives for e2e readiness checks.
Linked Issues check ✅ Passed The PR matches the linked issue goals by adding bounded polling, artifact numbering, migrations, and deterministic tests.
Out of Scope Changes check ✅ Passed The changes stay within the polling-foundation scope and representative readiness probe migrations described in the issue.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (6)
test/e2e/fixtures/polling.ts (2)

47-58: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Delay is executed even on the attempt that will immediately exceed the bound and fail.

When the final unsuccessful probe still has a positive delay, pollUntil sleeps before the next loop iteration discovers attempt > options.attempts (or the deadline has passed) and breaks — wasting a full delay cycle right before throwing. This adds real time to failing test runs (e.g. PROBE_DELAY_MS defaults to 5s in concurrent-gateway-ports.test.ts, and the deterministic test at Line 37 of e2e-polling.test.ts also captures this: delays [10, 20] include the delay after the last, doomed attempt).

♻️ Skip the trailing delay when no further attempt will run
     if (options.accept(value, attempt)) return lastAttempt;
+    const hasNextAttempt =
+      (options.attempts === undefined || attempt + 1 <= options.attempts) &&
+      (deadline === undefined || now() < deadline);
+    if (!hasNextAttempt) break;
     const delay =
       typeof options.delayMs === "function" ? options.delayMs(attempt) : (options.delayMs ?? 0);
     if (delay > 0) await sleep(delay);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/fixtures/polling.ts` around lines 47 - 58, In pollUntil, the delay
is applied after the last probe even when the next loop would immediately stop
because options.attempts or the deadline has been exceeded. Update the control
flow around the attempt loop in test/e2e/fixtures/polling.ts so the code checks
whether another attempt can still run before calling sleep, using the existing
pollUntil, options.attempts, deadline, and delay logic to skip the trailing
delay on a doomed final attempt.

45-46: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Abort signal isn't checked while a probe or sleep is in flight.

options.signal?.aborted is only checked at the top of the loop, so calling .abort() mid-sleep(delay) (or mid-probe) won't cancel until the current wait/probe completes — up to a full delayMs of extra latency.

♻️ Race sleep against the abort signal
-    if (delay > 0) await sleep(delay);
+    if (delay > 0) {
+      await Promise.race([
+        sleep(delay),
+        new Promise<void>((resolve) => options.signal?.addEventListener("abort", () => resolve(), { once: true })),
+      ]);
+    }

Also applies to: 55-57

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/fixtures/polling.ts` around lines 45 - 46, The polling loop in the
`polling` helper only checks `options.signal?.aborted` at the top of `for (let
attempt = 1; ; attempt += 1)`, so aborts during `sleep(delay)` or an in-flight
probe are delayed until the next iteration. Update the `polling` logic to race
both the probe and the delay against `options.signal` (or otherwise
short-circuit immediately on abort), and make the same change in the later
abort-sensitive section referenced by the `PollingError` flow so `abort()`
cancels promptly at any point in the wait cycle.
test/e2e/support/e2e-polling.test.ts (2)

19-39: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Test locks in an unnecessary sleep after the final permitted attempt before reporting exhaustion.

Tracing pollUntil: with attempts: 2 and delayMs: (attempt) => attempt * 10, the loop sleeps after attempt 2 fails (delays === [10, 20]) even though attempt 2 is the last one allowed — the extra 20ms delay is pure waste before the function throws. This test correctly documents current behavior, but the behavior itself means every migrated call site (e.g., waitForSandboxReady with PROBE_DELAY_MS defaulting to 5s) incurs one extra full delay on every readiness timeout before the failure is surfaced. Consider having pollUntil skip the trailing sleep when the attempt about to be incremented would exceed attempts/deadlineMs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/support/e2e-polling.test.ts` around lines 19 - 39, The pollUntil
behavior currently sleeps after the final allowed attempt before throwing
PollingError, which adds an unnecessary trailing delay. Update pollUntil so the
backoff sleep only happens when another probe will still run, using the
attempts/deadline checks before calling sleep. Keep the existing exhaustion
reporting and lastAttempt capture intact, and adjust the e2e polling test around
pollUntil to assert no extra sleep occurs on the final failed attempt.

41-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Deadline and terminal sub-tests are solid; abort coverage only exercises the pre-aborted case.

The abort assertion (Lines 64-74) only verifies behavior when the signal is already aborted before pollUntil is called. It doesn't exercise abort happening mid-poll (e.g., aborting inside probe after the first attempt), which is the more interesting path through the per-iteration signal?.aborted check. Consider adding a case where the signal is aborted between attempts to guard against future regressions in that check's placement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/support/e2e-polling.test.ts` around lines 41 - 75, The abort
coverage in pollUntil only checks a signal that is already aborted before the
call, so it misses the per-iteration abort path. Add a test case in the
e2e-polling suite that uses AbortController with polling.abort happening during
execution (for example, abort inside or immediately after the first probe call)
and assert that pollUntil rejects with the expected abort message. Keep the
existing deadline and terminal checks, and extend the abort coverage around
pollUntil, probe, and the signal-based loop handling.

Source: Path instructions

test/e2e/live/concurrent-gateway-ports.test.ts (1)

171-178: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Fragile string-match to distinguish terminal vs. exhaustion errors.

error.message.includes("terminal phase") couples this catch block to the exact wording produced by the terminal callback above (Line 167). If that message text is ever reworded, a genuine terminal-phase failure would silently fall through to the generic "did not reach Ready/Running" branch, losing the terminal diagnosis without any compile-time signal.

Since error.lastAttempt?.value already carries the parsed phase, recompute the terminal condition directly instead of parsing the message string.

♻️ Proposed fix: check phase directly instead of message text
   } catch (error) {
     if (!(error instanceof PollingError)) throw error;
-    if (error.message.includes("terminal phase")) throw error;
     const last = error.lastAttempt?.value;
+    const isTerminalPhase =
+      last?.phase === "Error" || last?.phase === "Failed" || last?.phase === "CrashLoopBackOff";
+    if (isTerminalPhase) throw error;
     throw new Error(
       `${sandboxName} did not reach Ready/Running on ${gatewayName}; last phase '${last?.phase ?? "missing"}'\n${last?.output ?? ""}`,
     );
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/live/concurrent-gateway-ports.test.ts` around lines 171 - 178, The
catch block in concurrent-gateway-ports.test.ts is using a fragile message
substring check to detect terminal-phase polling failures. Update the logic
around the PollingError handling so it determines terminal status from the
available attempt data instead of error.message text, ideally by inspecting
error.lastAttempt?.value.phase in the same branch that currently uses last and
the Ready/Running failure message. Keep the terminal-path rethrow behavior, but
make it independent of the wording produced by the PollingError terminal
callback.
test/e2e/live/network-policy-denied-log.ts (1)

35-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

delayMs: 1 is a magic value repurposed to trigger the injected sleep/settle hook.

pollUntil only invokes sleep when delay > 0 (per polling.ts), so delayMs: 1 here isn't a real delay duration — it exists solely to force options.settle() to run between probes. If a future edit "simplifies" this to delayMs: 0 (a more natural-looking value), settle() would silently stop being called between attempts, likely reintroducing flaky reads of not-yet-propagated logs. Worth a short comment or a named constant to make the intent explicit.

📝 Suggested clarifying comment
     const result = await pollUntil({
       artifactPrefix: "network-policy-denied-log",
       attempts: options.attempts,
-      delayMs: 1,
+      // Any positive value triggers `sleep` below between attempts; the actual
+      // wait is delegated to `options.settle()`, not this duration.
+      delayMs: 1,
       sleep: async () => options.settle(),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/live/network-policy-denied-log.ts` around lines 35 - 46, The current
pollUntil call uses delayMs: 1 only to force the injected sleep/settle hook to
run between probes, not to create a real wait. Keep the nonzero delay in
network-policy-denied-log.ts and make that intent explicit by introducing a
named constant or short explanatory comment near pollUntil, so future edits to
deniedReasonLogProof/options.settle do not “optimize” it to 0 and skip settle().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/e2e/fixtures/polling.ts`:
- Around line 23-30: `PollingError` currently only carries a free-text message,
so terminal, aborted, and exhausted polling failures can only be distinguished
by fragile message parsing. Add a structured discriminator on `PollingError`
(for example a `reason` field) in the class in `test/e2e/fixtures/polling.ts`,
and set it at each throw site in the polling helpers that currently create this
error. Update downstream consumers such as the concurrent-gateway-ports test to
branch on `error.reason` instead of checking `error.message.includes(...)`, so
terminal failures are classified reliably.

---

Nitpick comments:
In `@test/e2e/fixtures/polling.ts`:
- Around line 47-58: In pollUntil, the delay is applied after the last probe
even when the next loop would immediately stop because options.attempts or the
deadline has been exceeded. Update the control flow around the attempt loop in
test/e2e/fixtures/polling.ts so the code checks whether another attempt can
still run before calling sleep, using the existing pollUntil, options.attempts,
deadline, and delay logic to skip the trailing delay on a doomed final attempt.
- Around line 45-46: The polling loop in the `polling` helper only checks
`options.signal?.aborted` at the top of `for (let attempt = 1; ; attempt += 1)`,
so aborts during `sleep(delay)` or an in-flight probe are delayed until the next
iteration. Update the `polling` logic to race both the probe and the delay
against `options.signal` (or otherwise short-circuit immediately on abort), and
make the same change in the later abort-sensitive section referenced by the
`PollingError` flow so `abort()` cancels promptly at any point in the wait
cycle.

In `@test/e2e/live/concurrent-gateway-ports.test.ts`:
- Around line 171-178: The catch block in concurrent-gateway-ports.test.ts is
using a fragile message substring check to detect terminal-phase polling
failures. Update the logic around the PollingError handling so it determines
terminal status from the available attempt data instead of error.message text,
ideally by inspecting error.lastAttempt?.value.phase in the same branch that
currently uses last and the Ready/Running failure message. Keep the
terminal-path rethrow behavior, but make it independent of the wording produced
by the PollingError terminal callback.

In `@test/e2e/live/network-policy-denied-log.ts`:
- Around line 35-46: The current pollUntil call uses delayMs: 1 only to force
the injected sleep/settle hook to run between probes, not to create a real wait.
Keep the nonzero delay in network-policy-denied-log.ts and make that intent
explicit by introducing a named constant or short explanatory comment near
pollUntil, so future edits to deniedReasonLogProof/options.settle do not
“optimize” it to 0 and skip settle().

In `@test/e2e/support/e2e-polling.test.ts`:
- Around line 19-39: The pollUntil behavior currently sleeps after the final
allowed attempt before throwing PollingError, which adds an unnecessary trailing
delay. Update pollUntil so the backoff sleep only happens when another probe
will still run, using the attempts/deadline checks before calling sleep. Keep
the existing exhaustion reporting and lastAttempt capture intact, and adjust the
e2e polling test around pollUntil to assert no extra sleep occurs on the final
failed attempt.
- Around line 41-75: The abort coverage in pollUntil only checks a signal that
is already aborted before the call, so it misses the per-iteration abort path.
Add a test case in the e2e-polling suite that uses AbortController with
polling.abort happening during execution (for example, abort inside or
immediately after the first probe call) and assert that pollUntil rejects with
the expected abort message. Keep the existing deadline and terminal checks, and
extend the abort coverage around pollUntil, probe, and the signal-based loop
handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a118b360-b2e1-436a-b116-30d58dd57f0a

📥 Commits

Reviewing files that changed from the base of the PR and between b435598 and 017c3fe.

📒 Files selected for processing (4)
  • test/e2e/fixtures/polling.ts
  • test/e2e/live/concurrent-gateway-ports.test.ts
  • test/e2e/live/network-policy-denied-log.ts
  • test/e2e/support/e2e-polling.test.ts

Comment thread test/e2e/fixtures/polling.ts

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caller classifies PollingError by matching human-readable message substrings. Message edits can silently change aborted/terminal/exhausted control flow. Add a structured reason/kind to the error, branch on that field, and cover each outcome with tests. The stale growth-budget check should clear after synchronization with current main; rerun all checks after the fix.

@jyaunches
jyaunches force-pushed the refactor/e2e-bounded-polling branch from 017c3fe to be606d4 Compare July 7, 2026 12:28
@jyaunches

Copy link
Copy Markdown
Contributor Author

Addressed the requested structured polling failure classification in 6a906663a: PollingError now carries PollingFailureReason (aborted / terminal / exhausted), the polling helper sets the reason at each throw site, and concurrent-gateway-ports branches on error.reason === "terminal" instead of matching message text. Local validation passed: npm run typecheck -- --pretty false and npx vitest run --project e2e-support test/e2e/support/e2e-polling.test.ts. PR checks are green; ready for re-review.

@wscurran wscurran added v0.0.77 area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery refactor PR restructures code without intended behavior change and removed v0.0.76 labels Jul 7, 2026

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the current head. The structured PollingError.reason now replaces message-substring control flow, callers distinguish terminal from exhaustion, and tests cover exhausted, terminal, and aborted outcomes. Current-head CI and contributor-compliance gates are green.

@ericksoa ericksoa added v0.0.78 and removed v0.0.77 labels Jul 8, 2026
@cjagwani cjagwani added v0.0.79 and removed v0.0.78 labels Jul 8, 2026
@jyaunches
jyaunches merged commit 2c23cae into NVIDIA:main Jul 8, 2026
33 checks passed
@jyaunches jyaunches mentioned this pull request Jul 9, 2026
21 tasks
cv pushed a commit that referenced this pull request Jul 9, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Adds the pre-tag v0.0.79 release notes entry to
`docs/about/release-notes.mdx` so the release plan can be generated
after docs merge.
The entry summarizes the merged v0.0.79 release train across inference,
diagnostics, runtime hardening, policies, onboarding recovery, and
release validation.

## Changes
- Added the v0.0.79 release notes section with linked follow-up
documentation for OpenRouter onboarding, managed vLLM changes,
completion and logging, Deep Agents runtime limits, policy updates,
onboarding recovery, and release validation.
- Source summary:
- #6461 -> `docs/about/release-notes.mdx`: Documents OpenRouter
onboarding support and links to inference/provider references.
- #6271 and #6272 -> `docs/about/release-notes.mdx`: Documents shell
completion and structured logging highlights.
- #6465, #6539, #6570, and #6528 -> `docs/about/release-notes.mdx`:
Documents status route-drift, orphaned sandbox, gateway cleanup, and DGX
Spark express-install diagnostics.
- #6523, #6551, #6484, #6488, #6324, and #6542 ->
`docs/about/release-notes.mdx`: Documents managed vLLM, Qwen3.6 tool
parser, compaction, and timeout/readiness improvements.
- #6559, #6538, #6560, #6568, #6552, #6567, and #6587 ->
`docs/about/release-notes.mdx`: Documents runtime, credential, proxy,
PID namespace, TOML, and provider-state hardening.
- #6541, #5415, #6246, #6496, and #6573 ->
`docs/about/release-notes.mdx`: Documents GitHub policy, Gmail policy,
MCP allowlist, WhatsApp, and messaging-variant updates.
- #6253, #6572, #6444, #6536, and #5860 ->
`docs/about/release-notes.mdx`: Documents onboarding resume and
create-step recovery improvements.
- #6508, #6527, #5506, #6588, #6446, #6447, #6582, #6296, #6367, #6397,
and #6505 -> `docs/about/release-notes.mdx`: Documents docs,
release-risk, and E2E validation updates.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [x] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Quality Gates
<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: Release-note prose only.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification
<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result or justification: Tests
not applicable, release-note prose only.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

Docs validation note: `npm run docs:check-agent-variants && npm run
docs:check-routes && git diff --check` passed. Full `npm run docs` is
currently blocked before Fern validation because the pinned
`fern-api@5.65.2` package is unavailable from npm (`ETARGET No matching
version found`).

---
<!-- DCO sign-off is required in this PR description, and every commit
must appear as Verified in GitHub. Run: git config user.name && git
config user.email -->
Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added release notes for v0.0.79 with a new summary of recent
improvements, including onboarding and inference options, operator/CLI
diagnostics, sandbox recovery hardening, runtime limits, network policy
behavior, and release validation updates.
  * Added updated references and links for the latest release.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
…ks (NVIDIA#6367)

## Summary

Add a deterministic bounded-polling primitive for read-only readiness
checks and migrate representative sandbox-readiness and denied-log
probes. State-mutating installer/onboard/rebuild retries remain
explicit.

Closes NVIDIA#6347
Parent epic: NVIDIA#6346

## Changes

- Support attempt and deadline bounds, fixed/dynamic delay, abort
signals, terminal states, injected timing, and last-result diagnostics.
- Standardize attempt-numbered artifact names.
- Migrate concurrent-gateway sandbox readiness and denied network-policy
log polling.
- Add deterministic support tests for success, exhaustion, backoff,
deadlines, terminal states, and cancellation.

## Verification

- [x] Signed/Verified commit and all hooks passed
- [x] `npm run build:cli`
- [x] `npm run typecheck:cli`
- [x] `npm run lint`
- [x] Polling and denied-log support tests: 7 passed
- [x] No mutation retries hidden by the generic helper

---
Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a shared end-to-end polling helper with retries,
attempt/deadline bounds, configurable delays, abort-signal cancellation,
and standardized per-attempt artifact naming.

* **Bug Fixes**
* Refactored live readiness and denied-log polling to use the shared
helper, with consistent terminal-state handling and more informative
failures that include the last observed outcome.

* **Tests**
* Added an e2e test suite covering polling success, retry timing,
artifact naming, deadline/terminal early termination, and abort
cancellation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Adds the pre-tag v0.0.79 release notes entry to
`docs/about/release-notes.mdx` so the release plan can be generated
after docs merge.
The entry summarizes the merged v0.0.79 release train across inference,
diagnostics, runtime hardening, policies, onboarding recovery, and
release validation.

## Changes
- Added the v0.0.79 release notes section with linked follow-up
documentation for OpenRouter onboarding, managed vLLM changes,
completion and logging, Deep Agents runtime limits, policy updates,
onboarding recovery, and release validation.
- Source summary:
- NVIDIA#6461 -> `docs/about/release-notes.mdx`: Documents OpenRouter
onboarding support and links to inference/provider references.
- NVIDIA#6271 and NVIDIA#6272 -> `docs/about/release-notes.mdx`: Documents shell
completion and structured logging highlights.
- NVIDIA#6465, NVIDIA#6539, NVIDIA#6570, and NVIDIA#6528 -> `docs/about/release-notes.mdx`:
Documents status route-drift, orphaned sandbox, gateway cleanup, and DGX
Spark express-install diagnostics.
- NVIDIA#6523, NVIDIA#6551, NVIDIA#6484, NVIDIA#6488, NVIDIA#6324, and NVIDIA#6542 ->
`docs/about/release-notes.mdx`: Documents managed vLLM, Qwen3.6 tool
parser, compaction, and timeout/readiness improvements.
- NVIDIA#6559, NVIDIA#6538, NVIDIA#6560, NVIDIA#6568, NVIDIA#6552, NVIDIA#6567, and NVIDIA#6587 ->
`docs/about/release-notes.mdx`: Documents runtime, credential, proxy,
PID namespace, TOML, and provider-state hardening.
- NVIDIA#6541, NVIDIA#5415, NVIDIA#6246, NVIDIA#6496, and NVIDIA#6573 ->
`docs/about/release-notes.mdx`: Documents GitHub policy, Gmail policy,
MCP allowlist, WhatsApp, and messaging-variant updates.
- NVIDIA#6253, NVIDIA#6572, NVIDIA#6444, NVIDIA#6536, and NVIDIA#5860 ->
`docs/about/release-notes.mdx`: Documents onboarding resume and
create-step recovery improvements.
- NVIDIA#6508, NVIDIA#6527, NVIDIA#5506, NVIDIA#6588, NVIDIA#6446, NVIDIA#6447, NVIDIA#6582, NVIDIA#6296, NVIDIA#6367, NVIDIA#6397,
and NVIDIA#6505 -> `docs/about/release-notes.mdx`: Documents docs,
release-risk, and E2E validation updates.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [x] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Quality Gates
<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: Release-note prose only.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification
<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result or justification: Tests
not applicable, release-note prose only.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

Docs validation note: `npm run docs:check-agent-variants && npm run
docs:check-routes && git diff --check` passed. Full `npm run docs` is
currently blocked before Fern validation because the pinned
`fern-api@5.65.2` package is unavailable from npm (`ETARGET No matching
version found`).

---
<!-- DCO sign-off is required in this PR description, and every commit
must appear as Verified in GitHub. Run: git config user.name && git
config user.email -->
Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added release notes for v0.0.79 with a new summary of recent
improvements, including onboarding and inference options, operator/CLI
diagnostics, sandbox recovery hardening, runtime limits, network policy
behavior, and release validation updates.
  * Added updated references and links for the latest release.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery refactor PR restructures code without intended behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(e2e): add bounded polling primitives for live readiness checks

5 participants